﻿using System;

namespace Aeon.Emulator.Instructions
{
    /// <summary>
    /// Describes the machine code format expected for an instruction.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    internal sealed class OpcodeAttribute : Attribute
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the OpcodeAttribute class.
        /// </summary>
        /// <param name="opcodeFormat">Machine code format of the opcode and its operands.</param>
        public OpcodeAttribute(string opcodeFormat)
        {
            format = opcodeFormat;
            this.Epilog = ClearInEpilog.SegmentOverride | ClearInEpilog.OperandSize | ClearInEpilog.AddressSize | ClearInEpilog.Repeat;
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets the machine code format of the opcode and its operands.
        /// </summary>
        public string OpcodeFormat
        {
            get { return format; }
        }
        /// <summary>
        /// Gets or sets the name of the opcode.
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the opcode is a prefix.
        /// </summary>
        public bool IsPrefix { get; set; }
        /// <summary>
        /// Gets or sets the operand sizes that the method accepts.
        /// </summary>
        public int OperandSize
        {
            get { return operandSize; }
            set { operandSize = value; }
        }
        /// <summary>
        /// Gets or sets the address sizes that the method accepts.
        /// </summary>
        public int AddressSize
        {
            get { return addressSize; }
            set { addressSize = value; }
        }
        /// <summary>
        /// Gets or sets the state to be cleared in the instruction epilog.
        /// </summary>
        public ClearInEpilog Epilog { get; set; }
        #endregion

        #region Private Fields
        private string format;
        private int operandSize = 16;
        private int addressSize = 16;
        #endregion
    }

    /// <summary>
    /// Specifies processor state flags to clear in an instruction epilog.
    /// </summary>
    [Flags]
    internal enum ClearInEpilog
    {
        /// <summary>
        /// No instruction epilog.
        /// </summary>
        None = 0,
        /// <summary>
        /// Clear segment override.
        /// </summary>
        SegmentOverride = (1 << 0),
        /// <summary>
        /// Clear operand size override.
        /// </summary>
        OperandSize = (1 << 1),
        /// <summary>
        /// Clear address size override.
        /// </summary>
        AddressSize = (1 << 2),
        /// <summary>
        /// Clear repeat prefix.
        /// </summary>
        Repeat = (1 << 3)
    }
}
